#include "AsyncSockLite.h"
#include "../os/os_thread.h"
#include "../os/api.h"
#include "../os/os_socket.h"

#define SEND_DATA_LEN 1024*1024

CAsyncSockLite::CAsyncSockLite(void)
	:m_clsCritSection(0, "CAsyncSockLite", this)
{
	m_hSocket = OS_INVALID_SOCKET;

	m_bRun 		= false;
	m_bWrite 	= false;
}

CAsyncSockLite::~CAsyncSockLite(void)
{

}

bool CAsyncSockLite::Create()
{
	if( !CSockLite::Create() )
		return false;

	return true;
	//return Initialize();
}

void CAsyncSockLite::Close()
{
	bool bRun = false;
	{
		AUTO_LOCK(m_clsCritSection);

		if(m_bRun)
		{
			bRun = true;
			m_bRun = false;
		}
	}

	if(bRun)
	{
		os_thread_join(&m_thread);
		//os_thread_destroy(&m_thread);
	}
}

bool CAsyncSockLite::Connect( const char* lpszHostAddress, UINT nHostPort )
{
	//阻塞过程
	if( !CSockLite::Connect( lpszHostAddress, nHostPort ) )
	{
		if(HasError())
		{
			return false;
		}
	}

	Initialize();

	StartThread();

	return true;
}

bool CAsyncSockLite::Initialize()
{
	os_sock_ioctl_setnoblockio( m_hSocket);

	m_ReadBuffer.Clear();
	m_SendBuffer.Clear();

	return true;
}

void CAsyncSockLite::Uninitialize()
{
	os_thread_destroy(&m_thread);

	CSockLite::Close();
}

void CAsyncSockLite::StartThread()
{
	os_thread_create(&m_thread, WorkThread, this);

	os_thread_run(&m_thread);
}

int CAsyncSockLite::WorkThread( void* pParam )
{
	CAsyncSockLite* pThis = (CAsyncSockLite*)pParam;
	assert( NULL != pThis );

	pThis->RunStart();
	pThis->Run();
	pThis->RunEnd();

	return 0L;
}

void CAsyncSockLite::RunStart()
{
	// do nothing
	printf("CAsyncSockLite threadid = %d RunStart()\r\n", os_thread_id());
}

void CAsyncSockLite::RunEnd()
{
	printf("CAsyncSockLite threadid = %d RunEnd()\r\n", os_thread_id());

	{
		AUTO_LOCK(m_clsCritSection);
		m_SendBuffer.Clear();
		m_ReadBuffer.Clear();
	}

	Uninitialize();
}

void CAsyncSockLite::Run()
{
	m_bRun = true;

	m_bWrite = true;

	int nTickCount = 0;
	UINT lasttick = os_gettickcount();

	while(m_bRun)
	{
		struct timeval tv;
		tv.tv_sec = 0;
		tv.tv_usec = 1000;

		fd_set readfds;
		fd_set writefds;
		fd_set errorfds;
		FD_ZERO(&readfds);
		FD_ZERO(&writefds);
		FD_ZERO(&errorfds);
		FD_SET(m_hSocket, &readfds);
		FD_SET(m_hSocket, &errorfds);
		if(m_bWrite)
			FD_SET(m_hSocket, &writefds);

		int ret = select(m_hSocket + 1, &readfds, &writefds, &errorfds, &tv);
		if (ret < 0)
		{
			//assert (false);
			#ifndef WIN32
			if(errno == EINTR)
				continue;
			else
				break;
			#else
				break;
			#endif

		}

		if (FD_ISSET(m_hSocket, &writefds))
		{
			OnSend();
			m_bWrite = false;
		}
		if (FD_ISSET(m_hSocket, &readfds))
		{
			OnRead();
		}
		if (FD_ISSET(m_hSocket, &errorfds))
		{
			OnClose();
		}
	}
}

void CAsyncSockLite::OnRead()
{
	int nRecvLen = OnReceive();
	if(nRecvLen == 0)
	{
		OnClose();
	}
}

int CAsyncSockLite::OnReceive()
{
	int nTotalLen = 0;

	int nRecv = 0;
	bool bParse = false;

	do
	{
		char nTempBuffer[ 1024 ];
		nRecv = Receive( nTempBuffer, 1024 );
		if( nRecv > 0 )
		{
			//printf("recv data %s, len = %d\r\n", nTempBuffer, nRecv);
			m_ReadBuffer.Append( (BYTE*)nTempBuffer, nRecv );
			nTotalLen += nRecv;
			bParse = true;
		}
		if(nRecv < 1024)
			break;
	} while( 1 );

	if( bParse )
		Parse();


	return nTotalLen;
}

void CAsyncSockLite::OnSend()
{
	{
		AUTO_LOCK(m_clsCritSection);
		SendRemainPacket();
	}
}

void CAsyncSockLite::OnClose()
{
	m_bRun = false;
}

void CAsyncSockLite::OnHandleSendEvent()
{
	m_bWrite = true;
}

void CAsyncSockLite::Parse()
{
	printf("recv count %d \r\n", m_ReadBuffer.Size());

	m_ReadBuffer.Clear();

}

int CAsyncSockLite::SendRemainPacket()
{
	int nRet = 0;
	DWORD dwCurSend = 0;

	while( m_SendBuffer.Size() > 0 )
	{
		if( m_SendBuffer.Size() > SEND_DATA_LEN )
			dwCurSend = SEND_DATA_LEN;
		else
			dwCurSend = m_SendBuffer.Size();

		int nByteSend = CSockLite::Send( m_SendBuffer.Buffer(), dwCurSend );
		if( nByteSend == OS_SOCKET_ERROR )
		{
			break;
		}
		else
		{
			if( dwCurSend > (DWORD)nByteSend )
			{
				m_SendBuffer.ForwardHead( (DWORD)nByteSend );
				break;
			}

			m_SendBuffer.ForwardHead( dwCurSend );
			dwCurSend = 0;
		}
	}

	return nRet;
}

int CAsyncSockLite::Send(const void* lpBuf, int nBufLen)
{
 	AUTO_LOCK(m_clsCritSection);

	m_SendBuffer.Append((BYTE*)lpBuf, nBufLen);

	OnHandleSendEvent();

	return 1;
}

int	CAsyncSockLite::Send(std::list<CSerialBuffer>& lstBuffer)
{
	AUTO_LOCK(m_clsCritSection);
	for (std::list<CSerialBuffer>::iterator it = lstBuffer.begin(); it != lstBuffer.end(); it++)
	{
		CSerialBuffer& packet = *it;
		m_SendBuffer.Append(packet);
	}

	OnHandleSendEvent();

	return 1;
}

int	CAsyncSockLite::Send(CSerialBuffer& buffer)
{
	AUTO_LOCK(m_clsCritSection);
	m_SendBuffer.Append(&buffer);

	OnHandleSendEvent();

	return 1;
}
